
import { Color32 } from "../functions/image/color.js";
import { DrawArea, ImgTool } from "../functions/image/image.js";
import { RectRange } from "../functions/image/rect.js";
import { DrawLayer } from "./drawlayer.js";
import { Editor } from "./pixeleditor.js";

export abstract class DrawTool {
    //基础绘制
    protected editor: Editor
    constructor(editor: Editor) {
        this.editor = editor;
    }
    abstract OnLeftDown(area: DrawLayer, x: number, y: number, color: Color32): void
    abstract OnLeftMove(area: DrawLayer, x: number, y: number, color: Color32): void
    abstract OnLeftUp(area: DrawLayer, x: number, y: number, color: Color32): void
    OnToolMouseWheel(area: DrawLayer, delatvalue: number): void {

    }
    OnSet(): void {
        this.editor.toolbox_model.Hide();
        this.editor.toolbox_color.Show();
    }
    //预览绘制
    abstract OnPreview_InCanvas(priview: CanvasRenderingContext2D, x: number, y: number, offx: number, offy: number, pixelsizew: number, pixelsizeh: number, color: Color32): void

    abstract SetLineWidth(width: number): void;
    static DrawLine(c2d: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, x1: number, y1: number, x2: number, y2: number, color: Color32, width: number, scalew: number = 1, scaleh: number = 1): void {

        c2d.fillStyle = color.toString();
        let dx = x2 - x1;
        let dy = y2 - y1;
        let adx = Math.abs(dx);
        let ady = Math.abs(dy);
        let sdx = Math.sign(dx);
        let sdy = Math.sign(dy);
        let r = adx / ady;
        if (adx > ady) {

            for (var i = 0; i < adx; i++) {
                c2d.fillRect(((x1 + i * sdx) | 0) * scalew, ((y1 + i * sdy / r) | 0) * scaleh, (width * scalew) | 0, (width * scaleh) | 0);
            }
        }
        else {
            for (var i = 0; i < ady; i++) {
                c2d.fillRect(((x1 + i * sdx * r) | 0) * scalew, ((y1 + i * sdy) | 0) * scaleh, (width * scalew) | 0, (width * scaleh) | 0);
            }
        }
        //for循环有点问题，临时实现，不深究
        c2d.fillRect(x2 * scalew, y2 * scaleh, (width * scalew) | 0, (width * scaleh) | 0);
    }
    static DrawRect(c2d: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, x1: number, y1: number, x2: number, y2: number, color: Color32, width: number, scalew: number = 1, scaleh: number = 1): void {
        c2d.fillStyle = color.toString();
        let xx1 = Math.min(x1, x2);
        let xx2 = Math.max(x1, x2);
        let yy1 = Math.min(y1, y2);
        let yy2 = Math.max(y1, y2);
        for (var x = xx1; x <= xx2; x++) {
            c2d.fillRect((x | 0) * scalew, (y1 | 0) * scaleh, (width * scalew) | 0, (width * scaleh) | 0);
            c2d.fillRect((x | 0) * scalew, (y2 | 0) * scaleh, (width * scalew) | 0, (width * scaleh) | 0);
        }
        for (var y = yy1 + 1; y < yy2; y++) {
            c2d.fillRect((x1 | 0) * scalew, (y | 0) * scaleh, (width * scalew) | 0, (width * scaleh) | 0);
            c2d.fillRect((x2 | 0) * scalew, (y | 0) * scaleh, (width * scalew) | 0, (width * scaleh) | 0);
        }
    }
    //这样搞，半径是 sqrt (dx*dx +dy*dy)
    //这个效果的产生是个意外，但是效果还不错
    // static DrawCircle(c2d: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, x1: number, y1: number, x2: number, y2: number, color: Color32, width: number, scalew: number = 1, scaleh: number = 1): void {
    //     let cx = (x1 + x2) / 2
    //     let cy = (y1 + y2) / 2
    //     let dx = Math.abs(x2 - x1) / 2
    //     let dy = Math.abs(y2 - y1) / 2

    //     let lastcx = 0;
    //     let lastcy = 0;

    //     //this.DrawRect(c2d, cx, cy, cx + dx, cy + dy, color, width, scalew, scaleh);
    //     for (var i = 0; i <= 100; i++) {
    //         let rad = i * Math.PI * 2 / 100;


    //         let cirx = (Math.cos(rad) * dx + Math.sin(rad) * dx) + cx;
    //         let ciry = (-Math.sin(rad) * dy + Math.cos(rad) * dy) + cy;
    //         // cirx*=sx;
    //         // ciry*=sy;
    //         if (i > 0) {
    //             this.DrawLine(c2d, lastcx | 0, lastcy | 0, cirx | 0, ciry | 0, color, width, scalew, scaleh);
    //         }
    //         lastcx = cirx;
    //         lastcy = ciry;

    //     }
    // }
    //画正圆
    static DrawCircle_Perfect(c2d: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, x1: number, y1: number, x2: number, y2: number, color: Color32, width: number, scalew: number = 1, scaleh: number = 1): void {
        let cx = (x1 + x2) / 2
        let cy = (y1 + y2) / 2
        let dx = Math.abs(x2 - x1) / 2
        let dy = Math.abs(y2 - y1) / 2
        let r = Math.sqrt(dx * dx + dy * dy);
        let lastcx = 0;
        let lastcy = 0;

        //this.DrawRect(c2d, cx, cy, cx + dx, cy + dy, color, width, scalew, scaleh);
        for (var i = 0; i <= 100; i++) {
            let rad = i * Math.PI * 2 / 100;


            let cirx = (Math.cos(rad) * r) + cx;
            let ciry = (-Math.sin(rad) * r) + cy;
            // cirx*=sx;
            // ciry*=sy;
            if (i > 0) {
                this.DrawLine(c2d, lastcx | 0, lastcy | 0, cirx | 0, ciry | 0, color, width, scalew, scaleh);
            }
            lastcx = cirx;
            lastcy = ciry;

        }
    }


    static DrawCircle_InBox(c2d: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, x1: number, y1: number, x2: number, y2: number, color: Color32, width: number, scalew: number = 1, scaleh: number = 1): void {
        let cx = ((x1 + x2) / 2) | 0
        let cy = ((y1 + y2) / 2) | 0
        let dx = Math.abs(x2 - x1) / 2
        let dy = Math.abs(y2 - y1) / 2


        let lastcx = 0;
        let lastcy = 0;

        //this.DrawRect(c2d, cx, cy, cx + dx, cy + dy, color, width, scalew, scaleh);
        for (var i = 0; i <= 100; i++) {
            let rad = i * Math.PI * 2 / 100;
            let sin = Math.sin(rad);
            let cos = Math.cos(rad);

            let cirx = (cos * dx) + cx
            let ciry = (-sin * dy) + cy
            // cirx*=sx;
            // ciry*=sy;
            if (i > 0) {
                this.DrawLine(c2d, lastcx | 0, lastcy | 0, cirx | 0, ciry | 0, color, width, scalew, scaleh);
            }
            lastcx = cirx;
            lastcy = ciry;

        }
    }
}

export class Pencil_Tool extends DrawTool {

    linewidth: number = 1;
    SetLineWidth(width: number): void {
        this.linewidth = width;
    }
    x: number;
    y: number;
    OnLeftDown(area: DrawLayer, x: number, y: number, color: Color32): void {
        this.x = x;
        this.y = y;
        // area.DrawRect(x | 0, y | 0, this.linewidth, this.linewidth, color);
        let _r2d = area.getContext();
        _r2d.fillStyle = color.toString();
        _r2d.fillRect(x, y, this.linewidth, this.linewidth);
        area.updateBitmap();

    }
    OnLeftMove(area: DrawLayer, x: number, y: number, color: Color32): void {
        let _r2d = area.getContext();
        DrawTool.DrawLine(_r2d, this.x, this.y, x, y, color, this.linewidth);

        this.x = x;
        this.y = y;
        area.updateBitmap();
    }
    OnLeftUp(area: DrawLayer, x: number, y: number, color: Color32): void {
        this.editor.history.TrySave("铅笔");
    }
    OnPreview_InCanvas(priview: CanvasRenderingContext2D, x: number, y: number, offx: number, offy: number, pixelsizew: number, pixelsizeh: number, color: Color32): void {
        priview.fillStyle = color.toString();

        let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
        if (g < 0.6) {
            priview.strokeStyle = "#fff"
        }
        else {
            priview.strokeStyle = "#000"
        }
        x = (x - offx) | 0;
        y = (y - offy) | 0
        priview.fillRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        priview.strokeRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
    }

}
export class Earser_Tool extends DrawTool {
    linewidth: number = 1;
    SetLineWidth(width: number): void {
        this.linewidth = width;
    }
    OnSet(): void {

    }
    OnLeftDown(area: DrawLayer, x: number, y: number, color: Color32): void {
        area.ClearRect(x | 0, y | 0, this.linewidth, this.linewidth);
        area.updateBitmap();
    }
    OnLeftMove(area: DrawLayer, x: number, y: number, color: Color32): void {
        area.ClearRect(x | 0, y | 0, this.linewidth, this.linewidth);
        area.updateBitmap();
    }
    OnLeftUp(area: DrawLayer, x: number, y: number, color: Color32): void {
        this.editor.history.TrySave("橡皮");
    }
    OnPreview_InCanvas(priview: CanvasRenderingContext2D, x: number, y: number, offx: number, offy: number, pixelsizew: number, pixelsizeh: number, color: Color32): void {
        priview.fillStyle = "#fff"
        priview.strokeStyle = "#000";
        //priview.beginPath();

        x = (x - offx) | 0;
        y = (y - offy) | 0
        priview.fillRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        priview.strokeRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        // priview.closePath();
    }
}
export class DrawLine_Tool extends DrawTool {

    linewidth: number = 1;
    SetLineWidth(width: number): void {
        this.linewidth = width;
    }
    x: number;
    y: number;
    nx: number;
    ny: number;
    press: boolean;
    OnLeftDown(area: DrawLayer, x: number, y: number, color: Color32): void {
        this.x = x;
        this.y = y;
        this.nx = x;
        this.ny = y;
        this.press = true;
    }
    OnLeftMove(area: DrawLayer, x: number, y: number, color: Color32): void {

        this.nx = x;
        this.ny = y;

    }
    OnLeftUp(area: DrawLayer, x: number, y: number, color: Color32): void {
        this.press = false;
        let _r2d = area.getContext();
        DrawTool.DrawLine(_r2d, this.x, this.y, this.nx, this.ny, color, this.linewidth);
        _r2d.fillStyle = color.toString();

        area.updateBitmap();
        this.editor.history.TrySave("画线");
    }
    OnPreview_InCanvas(priview: CanvasRenderingContext2D, x: number, y: number, offx: number, offy: number, pixelsizew: number, pixelsizeh: number, color: Color32): void {
        if (this.press) {

            //画假线
            if (this.x != this.nx || this.y != this.ny) {
                priview.fillStyle = color.toString();

                let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
                if (g < 0.6) {
                    priview.strokeStyle = "#fff"
                }
                else {
                    priview.strokeStyle = "#000"
                }
                DrawTool.DrawLine(priview, this.x - offx, this.y - offy, this.nx - offx, this.ny - offy, color, this.linewidth, pixelsizew, pixelsizeh);
            }
        }
        {//画提示
            priview.fillStyle = color.toString();

            let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
            if (g < 0.6) {
                priview.strokeStyle = "#fff"
            }
            else {
                priview.strokeStyle = "#000"
            }
            x = (x - offx) | 0;
            y = (y - offy) | 0
            priview.fillRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
            priview.strokeRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        }
    }

}
export class DrawRect_Tool extends DrawTool {

    linewidth: number = 1;
    SetLineWidth(width: number): void {
        this.linewidth = width;
    }
    x: number;
    y: number;
    nx: number;
    ny: number;
    press: boolean;
    OnLeftDown(area: DrawLayer, x: number, y: number, color: Color32): void {
        this.x = x;
        this.y = y;
        this.nx = x;
        this.ny = y;
        this.press = true;
    }
    OnLeftMove(area: DrawLayer, x: number, y: number, color: Color32): void {

        this.nx = x;
        this.ny = y;

    }
    OnLeftUp(area: DrawLayer, x: number, y: number, color: Color32): void {
        this.press = false;
        let _r2d = area.getContext();
        DrawTool.DrawRect(_r2d, this.x, this.y, this.nx, this.ny, color, this.linewidth);
        _r2d.fillStyle = color.toString();

        area.updateBitmap();
        this.editor.history.TrySave("画矩形");
    }
    OnPreview_InCanvas(priview: CanvasRenderingContext2D, x: number, y: number, offx: number, offy: number, pixelsizew: number, pixelsizeh: number, color: Color32): void {
        if (this.press) {

            //画假线
            if (this.x != this.nx || this.y != this.ny) {
                priview.fillStyle = color.toString();

                let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
                if (g < 0.6) {
                    priview.strokeStyle = "#fff"
                }
                else {
                    priview.strokeStyle = "#000"
                }
                DrawTool.DrawRect(priview, this.x - offx, this.y - offy, this.nx - offx, this.ny - offy, color, this.linewidth, pixelsizew, pixelsizeh);
            }
        }
        {//画提示
            priview.fillStyle = color.toString();

            let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
            if (g < 0.6) {
                priview.strokeStyle = "#fff"
            }
            else {
                priview.strokeStyle = "#000"
            }
            x = (x - offx) | 0;
            y = (y - offy) | 0
            priview.fillRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
            priview.strokeRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        }
    }

}
export class Pick_Tool extends DrawTool {

    linewidth: number = 1;
    SetLineWidth(width: number): void {
        //this.linewidth = width;
    }
    OnLeftDown(area: DrawLayer, x: number, y: number, color: Color32): void {
        let data = area.getContext().getImageData(x, y, 1, 1);
        let c = new Color32(data.data[0], data.data[1], data.data[2], 255);
        this.editor.setDrawColor(c, true);
    }
    OnLeftMove(area: DrawLayer, x: number, y: number, color: Color32): void {
        let data = area.getContext().getImageData(x, y, 1, 1);
        let c = new Color32(data.data[0], data.data[1], data.data[2], 255);
        this.editor.setDrawColor(c, true);
    }
    OnLeftUp(area: DrawLayer, x: number, y: number, color: Color32): void {

    }
    OnPreview_InCanvas(priview: CanvasRenderingContext2D, x: number, y: number, offx: number, offy: number, pixelsizew: number, pixelsizeh: number, color: Color32): void {
        priview.fillStyle = "#fff"
        priview.strokeStyle = "#000";
        //priview.beginPath();

        x = (x - offx) | 0;
        y = (y - offy) | 0
        priview.fillRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        priview.strokeRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        // priview.closePath();
    }


}

export class Fill_Tool extends DrawTool {

    tranmode: boolean;
    constructor(editor: Editor, tranmode: boolean = false) {
        super(editor);

        this.tranmode = tranmode;
    }
    linewidth: number = 1;
    SetLineWidth(width: number): void {
        //this.linewidth = width;
    }
    OnSet(): void {
        if (this.tranmode == false) {
            super.OnSet();
        }
    }
    Color2Data(data: ImageData, x: number, y: number, c: Color32) {
        let seek = (y * data.width + x) * 4;
        data.data[seek + 0] = c.R;
        data.data[seek + 1] = c.G;
        data.data[seek + 2] = c.B;
        data.data[seek + 3] = c.A;
    }
    ColorFormData(data: ImageData, x: number, y: number): Color32 {
        let seek = (y * data.width + x) * 4;
        return new Color32(data.data[seek + 0], data.data[seek + 1], data.data[seek + 2], data.data[seek + 3]);
    }
    OnLeftDown(area: DrawLayer, x: number, y: number, color: Color32): void {
        let data = area.getContext().getImageData(0, 0, area.getWidth(), area.getHeight());
        let w = area.getWidth();
        let h = area.getHeight();
        let fillc: Color32 = this.ColorFormData(data, x, y);
        if (this.tranmode) {
            if (fillc.A == 0)
                return;

            color.R = 0;
            color.G = 0;
            color.B = 0;
            color.A = 0;
        }
        else {
            if (Color32.Equal(fillc, color)) {//启动色一样就不填充
                return;
            }
        }
        this.Color2Data(data, x, y, color);
        let nextpos: { x: number, y: number }[] = [];
        nextpos.push({ x: x, y: y });
        let steplimit = 1024 * 1024;//对步数做个限制
        while (nextpos.length > 0) {
            let nnext: { x: number, y: number }[] = [];
            for (var i = 0; i < nextpos.length; i++) {
                let px = nextpos[i].x;
                let py = nextpos[i].y;
                if (px > 0) {
                    let c = this.ColorFormData(data, px - 1, py);
                    if (Color32.Equal(c, fillc)) {
                        this.Color2Data(data, px - 1, py, color);
                        nnext.push({ x: px - 1, y: py });
                        steplimit--;
                    }
                }
                if (px + 1 < w) {
                    let c = this.ColorFormData(data, px + 1, py);
                    if (Color32.Equal(c, fillc)) {
                        this.Color2Data(data, px + 1, py, color);
                        nnext.push({ x: px + 1, y: py });
                        steplimit--;
                    }
                }
                if (py > 0) {
                    let c = this.ColorFormData(data, px, py - 1);
                    if (Color32.Equal(c, fillc)) {
                        this.Color2Data(data, px, py - 1, color);
                        nnext.push({ x: px, y: py - 1 });
                        steplimit--;
                    }
                }
                if (py + 1 < h) {
                    let c = this.ColorFormData(data, px, py + 1);
                    if (Color32.Equal(c, fillc)) {
                        this.Color2Data(data, px, py + 1, color);
                        nnext.push({ x: px, y: py + 1 });
                        steplimit--;
                    }
                }
            }

            nextpos = nnext;
        }


        area.getContext().putImageData(data, 0, 0);

        area.updateBitmap();


    }
    OnLeftMove(area: DrawLayer, x: number, y: number, color: Color32): void {

    }
    OnLeftUp(area: DrawLayer, x: number, y: number, color: Color32): void {

        this.editor.history.TrySave(this.tranmode ? "填充透明" : "填充");
    }
    OnPreview_InCanvas(priview: CanvasRenderingContext2D, x: number, y: number, offx: number, offy: number, pixelsizew: number, pixelsizeh: number, color: Color32): void {
        priview.fillStyle = color.toString();
        let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
        if (g < 0.6) {
            priview.strokeStyle = "#fff"
        }
        else {
            priview.strokeStyle = "#000"
        }
        //priview.beginPath();

        x = (x - offx) | 0;
        y = (y - offy) | 0
        priview.fillRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        priview.strokeRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        // priview.closePath();
    }


}


export class Select_Tool extends DrawTool {

    constructor(editor: Editor) {
        super(editor);
        this.editor = editor;
    }
    linewidth: number = 1;
    SetLineWidth(width: number): void {
        //this.linewidth = width;
    }
    OnSet(): void {

    }
    x: number;
    y: number;
    nx: number;
    ny: number;
    press: boolean;
    OnLeftDown(area: DrawLayer, x: number, y: number, color: Color32): void {
        this.x = x;
        this.y = y;
        this.nx = x;
        this.ny = y;
        this.press = true;

        area.Select_Cancel();
    }
    OnLeftMove(area: DrawLayer, x: number, y: number, color: Color32): void {

        this.nx = x;
        this.ny = y;
        if (this.x != this.nx || this.y != this.ny)
            area.Select(new RectRange(this.x, this.y, this.nx, this.ny));
        else
            area.Select_Cancel();
    }
    OnLeftUp(area: DrawLayer, x: number, y: number, color: Color32): void {
        this.press = false;
        if (this.x != this.nx || this.y != this.ny)
            area.Select(new RectRange(this.x, this.y, this.nx, this.ny));
        else
            area.Select_Cancel();

        this.editor.history.TrySave("选区变动");
    }
    OnPreview_InCanvas(priview: CanvasRenderingContext2D, x: number, y: number, offx: number, offy: number, pixelsizew: number, pixelsizeh: number, color: Color32): void {
        priview.fillStyle = "#fff"
        priview.strokeStyle = "#000";
        //priview.beginPath();

        x = (x - offx) | 0;
        y = (y - offy) | 0
        priview.fillRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        priview.strokeRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
    }

}

export class Move_Tool extends DrawTool {

    x: number;
    y: number;
    sx: number;
    sy: number;
    srcbitmap: ImageBitmap;
    scalev: number = 1.0;
    move: boolean = false;
    scale: boolean = false;
    srcsel: RectRange
    OnSet(): void {
        this.scalev = 1.0;
        this.move = false
        this.scale = false;
        this.srcbitmap = null;
    }

    OnLeftDown(area: DrawLayer, x: number, y: number, color: Color32): void {
        if (this.scale) {
            //area.applySelectData();
            //this.srcbitmap = area.getBitmapSelect();
            this.scalev = 1.0;
            this.scale = false;
        }

        this.x = x;
        this.y = y;



        if (area.getSelect() == null) {
            area.Select(new RectRange(0, 0, area.getWidth() - 1, area.getHeight() - 1));
        }

        if (!this.move) {
            //area.applySelectData();

            //area.cutDataToSelect();

            //this.srcbitmap = area.getBitmapSelect();


            let s = area.getSelect();
            this.srcsel = new RectRange(s.x1, s.y1, s.x2, s.y2);
            this.move = true;
            this.sx = 0;
            this.sy = 0;
        }

        if (area.getBitmapSelect() == null) {
            area.cutDataToSelect();
        }

        if (!this.srcbitmap)
            this.srcbitmap = area.getBitmapSelect();

    }
    OnLeftMove(area: DrawLayer, x: number, y: number, color: Color32): void {
        area.Select_ImgClear();

        area.Select_ImgDrawImage(this.srcbitmap, this.sx + (x - this.x), this.sy + (y - this.y));
        let selcect = area.getSelect();
        let w = selcect.x2 - selcect.x1;
        let h = selcect.y2 - selcect.y1;
        selcect.x1 = this.srcsel.x1 + this.sx + (x - this.x);
        selcect.y1 = this.srcsel.y1 + this.sy + (y - this.y);
        selcect.x2 = selcect.x1 + w;
        selcect.y2 = selcect.y1 + h;
        this.editor.drawCanvas.RePaint();
    }
    OnLeftUp(area: DrawLayer, x: number, y: number, color: Color32): void {
        this.sx += x - this.x;
        this.sy += y - this.y;

        this.move = true;
        this.editor.history.TrySave("选区移动");
    }
    OnPreview_InCanvas(priview: CanvasRenderingContext2D, x: number, y: number, offx: number, offy: number, pixelsizew: number, pixelsizeh: number, color: Color32): void {
        priview.fillStyle = color.toString();
        let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
        if (g < 0.6) {
            priview.strokeStyle = "#fff"
        }
        else {
            priview.strokeStyle = "#000"
        }
        //priview.beginPath();

        x = (x - offx) | 0;
        y = (y - offy) | 0
        priview.fillRect(x * pixelsizew, y * pixelsizeh, 1 * pixelsizew, 1 * pixelsizeh);
        priview.strokeRect(x * pixelsizew, y * pixelsizeh, 1 * pixelsizew, 1 * pixelsizeh);
    }
    SetLineWidth(width: number): void {


    }

    OnToolMouseWheel(area: DrawLayer, delatvalue: number): void {

        if (this.move) {
            //area.applySelectData();
            //this.srcbitmap = area.getBitmapSelect();
            this.move = false;
        }

        if (area.getSelect() == null) {
            area.Select(new RectRange(0, 0, area.getWidth() - 1, area.getHeight() - 1));
        }

        if (!this.scale) {
            let s = area.getSelect();
            this.srcsel = new RectRange(s.x1, s.y1, s.x2, s.y2);
            this.x = s.x2 - s.x1;
            this.y = s.y2 - s.y1;
            this.sx = (s.x2 + s.x1) / 2;
            this.sy = (s.y2 + s.y1) / 2;

            this.scale = true;
        }

        if (area.getBitmapSelect() == null) {
            area.cutDataToSelect();

        }
        if (this.srcbitmap == null)
            this.srcbitmap = area.getBitmapSelect();

        area.Select_ImgClear();
        if (delatvalue > 0)
            this.scalev *= 2;
        else
            this.scalev /= 2;
        if (this.scalev > 4)
            this.scalev = 4;
        if (this.scalev < 0.125)
            this.scalev = 0.125
        area.Select_ImgDrawImageScale(this.srcbitmap, this.srcsel, this.scalev, this.scalev);


        let s = area.getSelect();

        let w = this.x;
        let h = this.y;
        let cx = this.sx;
        let cy = this.sy;
        s.x1 = (cx - (w / 2) * this.scalev) | 0
        s.y1 = (cy - (h / 2) * this.scalev) | 0
        s.x2 = (cx + (w / 2) * this.scalev) | 0
        s.y2 = (cy + (h / 2) * this.scalev) | 0

        // if (s.x1 < 0) {
        //     s.x1 = 0;
        // }
        // if (s.y1 < 0) {
        //     s.y1 = 0;

        // }
        // if (s.x2 >= area.getWidth())
        //     s.x2 = area.getWidth() - 1;
        // if (s.y2 >= area.getHeight())
        //     s.y2 = area.getHeight() - 1;





        this.editor.drawCanvas.RePaint();

    }

}
export class Rotate_Tool extends DrawTool {

    x: number;
    y: number;
    sx: number;
    sy: number;
    srcbitmap: ImageBitmap;
    rotate: boolean = false;
    rotatevalue: number = 0;
    OnSet(): void {
        this.rotatevalue = 0;
        this.rotate = false;
        this.srcbitmap = null;
    }
    OnLeftDown(area: DrawLayer, x: number, y: number, color: Color32): void {
        this.x = x;
        this.y = y;

        if (this.rotate == false) {
            //area.applySelectData();
            this.srcbitmap = area.getBitmapSelect();
        }
        // if (area.getBitmapSelect() != null) {
        //     area.applySelectData();
        // }

        if (area.getSelect() == null) {
            area.Select(new RectRange(0, 0, area.getWidth() - 1, area.getHeight() - 1));
        }
        this.sx = (area.getSelect().x1 + area.getSelect().x2) / 2;
        this.sy = (area.getSelect().y1 + area.getSelect().y2) / 2;

        //select区域没东西时，才copy
        if (area.getBitmapSelect() == null) {
            area.cutDataToSelect();

        }
        if (this.srcbitmap == null)
            this.srcbitmap = area.getBitmapSelect();

    }
    OnLeftMove(area: DrawLayer, x: number, y: number, color: Color32): void {
        area.Select_ImgClear();
        let a = ((x - this.x) + (y - this.y)) / 100 * Math.PI;

        let rotate = this.rotatevalue + a;
        //this.rotatevalue = Math.PI / 2;
        area.Select_ImgDrawImage(this.srcbitmap, -this.sx, -this.sy, this.sx, this.sy, rotate);//a) ;
        // let selcect = area.getSelect();
        // let w = selcect.x2 - selcect.x1;
        // let h = selcect.y2 - selcect.y1;
        // selcect.x1 = this.sx + (x - this.x);
        // selcect.y1 = this.sy + (y - this.y);
        // selcect.x2 = selcect.x1 + w;
        // selcect.y2 = selcect.y1 + h;
        this.editor.drawCanvas.RePaint();
        this.rotate = true;
    }
    OnLeftUp(area: DrawLayer, x: number, y: number, color: Color32): void {
        this.rotate = true;
        let a = ((x - this.x) + (y - this.y)) / 100 * Math.PI;
        this.rotatevalue += a;
        this.editor.history.TrySave("选区旋转");
    }
    OnPreview_InCanvas(priview: CanvasRenderingContext2D, x: number, y: number, offx: number, offy: number, pixelsizew: number, pixelsizeh: number, color: Color32): void {
        priview.fillStyle = color.toString();
        let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
        if (g < 0.6) {
            priview.strokeStyle = "#fff"
        }
        else {
            priview.strokeStyle = "#000"
        }
        //priview.beginPath();

        x = (x - offx) | 0;
        y = (y - offy) | 0
        priview.fillRect(x * pixelsizew, y * pixelsizeh, 1 * pixelsizew, 1 * pixelsizeh);
        priview.strokeRect(x * pixelsizew, y * pixelsizeh, 1 * pixelsizew, 1 * pixelsizeh);
    }
    SetLineWidth(width: number): void {


    }

}
export enum DrawCircle_Mode {
    Center,
    TwoPoint,
    OutRect
}
export class DrawCircle_Tool extends DrawTool {

    constructor(editor: Editor, mode: DrawCircle_Mode) {
        super(editor);
        this.mode = mode;
    }
    mode: DrawCircle_Mode
    linewidth: number = 1;
    SetLineWidth(width: number): void {
        this.linewidth = width;
    }
    x: number;
    y: number;
    nx: number;
    ny: number;
    press: boolean;
    OnLeftDown(area: DrawLayer, x: number, y: number, color: Color32): void {
        this.x = x;
        this.y = y;
        this.nx = x;
        this.ny = y;
        this.press = true;
    }
    OnLeftMove(area: DrawLayer, x: number, y: number, color: Color32): void {

        this.nx = x;
        this.ny = y;

    }
    OnLeftUp(area: DrawLayer, x: number, y: number, color: Color32): void {
        this.press = false;
        let _r2d = area.getContext();
        if (this.mode == DrawCircle_Mode.Center) {
            let x1 = this.x - (this.nx - this.x);
            let y1 = this.y - (this.ny - this.y);
            DrawTool.DrawCircle_Perfect(_r2d, x1, y1, this.nx, this.ny, color, this.linewidth);
        }
        else if (this.mode == DrawCircle_Mode.TwoPoint) {
            DrawTool.DrawCircle_Perfect(_r2d, this.x, this.y, this.nx, this.ny, color, this.linewidth);
        }
        else if (this.mode == DrawCircle_Mode.OutRect) {
            DrawTool.DrawCircle_InBox(_r2d, this.x, this.y, this.nx, this.ny, color, this.linewidth);
        }

        _r2d.fillStyle = color.toString();

        area.updateBitmap();
        this.editor.history.TrySave("画圆");
    }
    OnPreview_InCanvas(priview: CanvasRenderingContext2D, x: number, y: number, offx: number, offy: number, pixelsizew: number, pixelsizeh: number, color: Color32): void {

        if (this.press) {

            //画假线
            if (this.x != this.nx || this.y != this.ny) {
                priview.fillStyle = color.toString();

                let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
                if (g < 0.6) {
                    priview.strokeStyle = "#fff"
                }
                else {
                    priview.strokeStyle = "#000"
                }
                if (this.mode == DrawCircle_Mode.Center) {
                    let x1 = this.x - (this.nx - this.x);
                    let y1 = this.y - (this.ny - this.y);
                    DrawTool.DrawCircle_Perfect(priview, x1 - offx, y1 - offy, this.nx - offx, this.ny - offx, color, this.linewidth, pixelsizew, pixelsizeh);
                }
                else if (this.mode == DrawCircle_Mode.TwoPoint) {
                    DrawTool.DrawCircle_Perfect(priview, this.x - offx, this.y - offy, this.nx - offx, this.ny - offy, color, this.linewidth, pixelsizew, pixelsizeh);
                }
                else if (this.mode == DrawCircle_Mode.OutRect) {
                    DrawTool.DrawCircle_InBox(priview, this.x - offx, this.y - offy, this.nx - offx, this.ny - offy, color, this.linewidth, pixelsizew, pixelsizeh);
                }
            }
        }
        {//画提示
            priview.fillStyle = color.toString();

            let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
            if (g < 0.6) {
                priview.strokeStyle = "#fff"
            }
            else {
                priview.strokeStyle = "#000"
            }
            x = (x - offx) | 0;
            y = (y - offy) | 0
            priview.fillRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
            priview.strokeRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        }
    }

}
//摆放模板图片
export class Model_Tool extends DrawTool {
    Align: number = 1;
    OnSet(): void {
        this.editor.toolbox_model.Show();
        this.editor.toolbox_color.Hide();
    }
    OnLeftDown(area: DrawLayer, x: number, y: number, color: Color32): void {
        let img = this.editor.toolbox_model_bar.getPickImg();
        if (img == null)
            return;
        let _r2d = area.getContext();

        x = ((x / this.Align) | 0) * this.Align;
        y = ((y / this.Align) | 0) * this.Align;


        _r2d.drawImage(img, x, y);
        area.updateBitmap();
        this.editor.history.TrySave("拜访模板");
    }
    OnLeftMove(area: DrawLayer, x: number, y: number, color: Color32): void {

    }
    OnLeftUp(area: DrawLayer, x: number, y: number, color: Color32): void {

    }
    OnPreview_InCanvas(priview: CanvasRenderingContext2D, x: number, y: number, offx: number, offy: number, pixelsizew: number, pixelsizeh: number, color: Color32): void {


        let img = this.editor.toolbox_model_bar.getPickImg();
        if (img == null)
            return;
        x = ((x / this.Align) | 0) * this.Align;
        y = ((y / this.Align) | 0) * this.Align;


        x = (x - offx) | 0;
        y = (y - offy) | 0

        priview.globalAlpha = 0.5;
        priview.drawImage(img, 0, 0, img.width, img.height, x * pixelsizew, y * pixelsizeh, img.width * pixelsizew, img.height * pixelsizeh);
        priview.globalAlpha = 1;
        //priview.strokeRect(x * pixelsizew, y * pixelsizeh, 1 * pixelsizew, 1 * pixelsizeh);
    }
    SetLineWidth(width: number): void {

    }

}
export class DrawToolCenter {
    private static mapTool: { [id: string]: DrawTool } = {};
    static Init(editor: Editor) {

        this.mapTool["pencil"] = new Pencil_Tool(editor);

        this.mapTool["earse"] = new Earser_Tool(editor);


        this.mapTool["drawline"] = new DrawLine_Tool(editor);

        this.mapTool["drawrect"] = new DrawRect_Tool(editor);

        this.mapTool["drawcircle1"] = new DrawCircle_Tool(editor, DrawCircle_Mode.Center);
        this.mapTool["drawcircle2"] = new DrawCircle_Tool(editor, DrawCircle_Mode.TwoPoint);
        this.mapTool["drawcircle_out"] = new DrawCircle_Tool(editor, DrawCircle_Mode.OutRect);


        this.mapTool["pick"] = new Pick_Tool(editor);

        this.mapTool["fill"] = new Fill_Tool(editor);
        this.mapTool["filltran"] = new Fill_Tool(editor, true);

        this.mapTool["select"] = new Select_Tool(editor);
        this.mapTool["move"] = new Move_Tool(editor);
        this.mapTool["rotate"] = new Rotate_Tool(editor);

        this.mapTool["model"] = new Model_Tool(editor);
    }
    static GetDrawTool(tag: string): DrawTool {
        let tool = this.mapTool[tag];

        return tool;
    }

}